Как было отмечено ранее, одной из основных проблем, которые приходится решать при создании больших и сложных систем любой природы, в том числе и ПО, является проблема сложности. Ни один разработчик не в состоянии выйти за пределы человеческих возможностей и понять всю систему в целом. Единственный эффективный подход к решению этой проблемы, который выработало человечество за всю свою историю, заключается в построении сложной системы из небольшого количества крупных частей, каждая из которых, в свою очередь, строится из частей меньшего размера, и т.д., до тех пор, пока самые небольшие части можно будет строить из имеющегося материала. Этот подход известен под самыми разными названиями, среди них такие, как «разделяй и властвуй» (divide et imperd), иерархическая декомпозиция и др. По отношению к проектированию сложной программной системы это означает, что ее необходимо разделить (декомпозировать) на небольшие подсистемы, каждую из которых можно разрабатывать независимо от других. Это позволяет при разработке подсистемы любого уровня иметь дело только с ней, а не со всеми остальными частями системы. Правильная декомпозиция является главным способом преодоления сложности разработки больших систем ПО. Понятие «правильная» по отношению к декомпозиции означает следующее:
• количество связей между отдельными подсистемами должно быть минимальным (принцип «слабой связанности» - Low Coupling);
• связность отдельных частей внутри каждой подсистемы должна быть максимальной (принцип «сильного сцепления» — High Cohesion).
Структура системы должна быть такой, чтобы все взаимодействия между ее подсистемами укладывались в ограниченные, стандартные рамки, т.е.:
• каждая подсистема должна инкапсулировать свое содержимое (скрывать его от других подсистем);
• каждая подсистема должна иметь четко определенный интерфейс с другими подсистемами.
Инкапсуляция (принцип «черного ящика») позволяет рассматривать структуру каждой подсистемы независимо от других подсистем. Интерфейсы позволяют строить систему более высокого уровня, рассматривая каждую подсистему как единое целое и игнорируя ее внутреннее устройство.
Существуют два основных подхода к декомпозиции систем. Первый подход называют функционально-модульным, он является частью более общего структурного подхода. В его основу положен принцип функциональной декомпозиции, при которой структура системы описывается в терминах иерархии ее функций и передачи информации между отдельными функциональными элементами. Второй, объектно-ориентированный подход, использует объектную декомпозицию. При этом структура системы описывается в терминах объектов и связей между ними, а поведение системы описывается в терминах обмена сообщениями между объектами.
В 1970-1980 годах при разработке ПО достаточно широко применялись структурные методы, предоставляющие в распоряжение разработчиков строгие формализованные методы описания проектных решений - спецификаций ПО (в настоящее время такое же распространение получают объектно-ориентированные методы). Эти методы основаны на использовании наглядных графических моделей: для описания архитектуры ПО с различных точек зрения (как статической структуры, так и динамики поведения системы) используются схемы и диаграммы. Наглядность и строгость средств структурного и объектно-ориентированного анализа позволяет разработчикам и будущим пользователям системы с самого начала неформально участвовать в ее создании, обсуждать и закреплять понимание основных технических решений. Однако широкое применение этих методов и следование их рекомендациям при разработке конкретных систем ПО сдерживалось отсутствием адекватных инструментальных средств, поскольку при неавтоматизированной (ручной) разработке все их преимущества практически сведены к нулю. Действительно, вручную очень трудно разработать и графически представить строгие формальные спецификации системы, проверить их на полноту и непротиворечивость и тем более изменить. Если все же удается создать строгую систему проектных документов, то ее переработка при появлении серьезных изменений практически неосуществима. Ручная разработка обычно порождала следующие проблемы:
• неадекватная спецификация требований;
• неспособность обнаруживать ошибки в проектных решениях;
• низкое качество документации, снижающее эксплуатационные характеристики;
• затяжной цикл и неудовлетворительные результаты тестирования.
С другой стороны, разработчики ПО исторически всегда стояли последними в ряду тех, кто использовал компьютерные технологии для повышения качества, надежности и производительности в своей собственной работе (феномен «сапожника без сапог»).
Перечисленные факторы способствовали появлению программно-технологических средств специального класса - CASE-средств, реализующих CASE-технологию создания ПО. Понятие CASE (Computer Aided Software Engineering) используется в настоящее время в весьма широком смысле. Первоначальное значение этого понятия, ограниченное только задачами автоматизации разработки ПО, в настоящее время приобрело новый смысл, охватывающий большинство процессов жизненного цикла ПО.
Появлению CASE-технологии и CASE-средств предшествовали исследования в области программирования: разработка и внедрение языков высокого уровня, методов структурного и модульного программирования, языков проектирования и средств их поддержки, формальных и неформальных языков описаний системных требований и спецификаций и т.д. Кроме того, этому способствовали следующие факторы:
• подготовка аналитиков и программистов, восприимчивых к концепциям модульного и структурного программирования;
• широкое внедрение и постоянный рост производительности компьютеров, позволившие использовать эффективные графические средства и автоматизировать большинство этапов проектирования;
• внедрение сетевой технологии, предоставившей возможность объединения усилий отдельных исполнителей в единый процесс проектирования путем использования разделяемой базы данных, содержащей необходимую информацию о проекте.
CASE-технология представляет собой совокупность методов проектирования ПО, а также набор инструментальных средств, позволяющих в наглядной форме моделировать предметную область, анализировать эту модель на всех стадиях разработки и сопровождения ПО и разрабатывать приложения в соответствии с информационными потребностями пользователей. Большинство существующих CASE-средств основано на методах структурного или объектно-ориентированного анализа и проектирования, использующих спецификации в виде диаграмм или текстов для описания внешних требований, связей между моделями системы, динамики поведения системы и архитектуры программных средств.
Под моделью ПО в общем случае понимается формализованное описание системы ПО на определенном уровне абстракции. Каждая модель определяет конкретный аспект системы, использует набор диаграмм и документов заданного формата, а также отражает точку зрения и является объектом деятельности различных людей с конкретными интересами, ролями или задачами.
Под термином «моделирование» понимается процесс создания формализованного описания системы в виде совокупности моделей. Особенно трудным оказывается описание систем средней сложности, таких, как система коммутаций в телефонных сетях, управление авиаперевозками или движением подводной лодки, сборка автомобилей, челночные космические рейсы, функционирование перерабатывающих предприятий (к таким системам относится и ПО). С точки зрения человека, эти системы описать достаточно трудно, потому что они настолько велики, что практически невозможно перечислить все их компоненты со своими взаимосвязями, и в то же время недостаточно велики для применения общих упрощающих предположений (как это принято в физике). Неспособность дать простое описание, а, следовательно, и обеспечить понимание таких систем делает их проектирование и создание трудоемким и дорогостоящим процессом и повышает степень их ненадежности. С ростом технического прогресса адекватное описание систем становится все более актуальной проблемой.
Модель должна давать полное, точное и адекватное описание системы, имеющее конкретное назначение. Это назначение, называемое целью модели, вытекает из формального определения модели:
М есть модель системы S, если М может быть использована для получения ответов на вопросы относительно S с точностью А.
Таким образом, целью модели является получение ответов на некоторую совокупность вопросов. Эти вопросы неявно присутствуют (подразумеваются) в процессе анализа и, следовательно, они руководят созданием модели и направляют его. Это означает, что сама модель должна будет дать ответы на эти вопросы с заданной степенью точности. Если модель отвечает не на все вопросы или ее ответы недостаточно точны, то говорят, что модель не достигла своей цели.
По мнению авторитетных специалистов в области проектирования ПО, моделирование является центральным звеном всей деятельности по созданию систем ПО. Модели строятся для того, чтобы понять и осмыслить структуру и поведение будущей системы, облегчить управление процессом ее создания и уменьшить возможный риск, а также документировать принимаемые проектные решения.
Визуальное моделирование — это способ восприятия проблем с помощью зримых абстракций, воспроизводящих понятия и объекты реального мира. Модели служат полезным инструментом анализа проблем, обмена информацией между всеми заинтересованными сторонами (пользователями, специалистами в предметной области, аналитиками, проектировщиками и т.д.), проектирования ПО, а также подготовки документации. Моделирование способствует более полному усвоению требований, улучшению качества системы и повышению степени ее управляемости.
С помощью модели можно упростить проблему, отбросив несущественные детали и сосредоточив внимание на главном. Способность к абстрагированию — это фундаментальное свойство человеческого интеллекта, помогающее справиться с феноменом сложности. На протяжении тысяч лет художники, ремесленники и строители предпринимали попытки конструирования тех или иных моделей, предваряющие реальное воплощение творческих замыслов. Не составляет исключения и индустрия разработки ПО. Чтобы создать сложную программную систему, разработчики должны абстрагировать ее свойства с разных точек зрения, с помощью точных нотаций (систем обозначений) сконструировать адекватные модели, удостовериться, удовлетворяют ли они исходным требованиям, а затем реализовать модели на практике, постепенно пополняя систему новыми функциями.
К моделированию сложных систем приходится прибегать ввиду того, что мы не в состоянии постичь их единовременно во всей полноте. Способность человека к восприятию сложных вещей имеет свои естественные границы. В этом легко убедиться, обратившись к сфере строительства и архитектуры. Если нужно построить курятник, за работу можно приняться тотчас; если речь идет о новом доме, тогда, вероятно, потребуется хотя бы эскиз; наконец, при возведении небоскреба без точных расчетов и чертежей обойтись уже явно не удастся. Те же законы действуют и в мире программирования. Делая главную ставку на написание строк исходного кода или даже на использование форм Visual Basic, разработчик вряд ли сможет сколько-нибудь полно охватить структуру объемного проекта в целом. Предварительное моделирование, в свою очередь, позволяет проектировщику увидеть общую картину взаимодействий компонентов проекта без необходимости анализа особых свойств каждого компонента.
Графические (визуальные) модели представляют собой средства для визуализации, описания, проектирования и документирования архитектуры системы. Под архитектурой понимается набор основных правил, определяющих организацию системы:
• совокупность структурных элементов системы и связей между ними;
• поведение элементов системы в процессе их взаимодействия;
• иерархию подсистем, объединяющих структурные элементы;
• архитектурный стиль (используемые методы и средства описания архитектуры, а также архитектурные образцы).
Архитектура является многомерной, поскольку различные специалисты работают с различными ее аспектами. Например, при строительстве здания используются разные типы чертежей, представляющие различные аспекты архитектуры:
• планы этажей;
• вертикальные проекции;
• планы монтажа кабельной проводки;
• чертежи водопроводов, системы центрального отопления и вентиляции;
• вид здания на фоне местности (эскизы).
Архитектура ПО также предусматривает различные представления, служащие разным целям:
• представлению функциональных возможностей системы;
• отображению логической организации системы;
• описанию физической структуры программных компонентов в среде реализации;
• отображению структуры потоков управления и аспектов параллельной работы;
• описанию физического размещения программных компонентов на базовой платформе.
Архитектурное представление — это упрощенное описание (абстракция) системы с конкретной точки зрения, охватывающее определенный круг интересов и опускающее объекты, несущественные с данной точки зрения. Архитектурные представления концентрируют внимание только на элементах, значимых с точки зрения архитектуры. Архитектурно значимый элемент — это элемент, имеющий значительное влияние на структуру системы и ее производительность, надежность и возможность развития. Это элемент, важный для понимания системы. Например, в состав архитектурно значимых элементов объектно-ориентированной архитектуры входят основные классы предметной области, подсистемы и их интерфейсы, основные процессы или потоки управления.
Архитектурные представления подобны сечениям различных моделей, выделяющим только важные, значимые элементы моделей.
Разработка модели архитектуры системы ПО промышленного характера на стадии, предшествующей ее реализации или обновлению, в такой же мере необходима, как и наличие проекта для строительства большого здания. Это утверждение справедливо как в случае разработки новой системы, так и при адаптации типовых продуктов класса R/3 или BAAN, в составе которых также имеются собственные средства моделирования. Хорошие мо¬дели являются основой взаимодействия участников проекта и гарантируют корректность архитектуры. Поскольку сложность систем повышается, важно располагать хорошими методами моделирования. Хотя имеется много других факторов, от которых зависит успех проекта, но наличие строгого стандарта языка моделирования является весьма существенным. Язык моделирования включает:
• элементы модели - фундаментальные концепции моделирования и их семантику;
• нотацию (систему обозначений) — визуальное представление элементов моделирования;
• руководство по использованию — правила применения элементов в рамках построения тех или иных типов моделей ПО.
Очевидно, что конечная цель разработки ПО — это не моделирование, а получение работающих приложений (кода). Диаграммы, в конечном счете — это всего лишь наглядные изображения. Создание слишком большого количества диаграмм до начала программирования займет слишком много времени и не обеспечит построения готовой системы. Поэтому при использовании графических языков моделирования очень важно понимать, чем это поможет, когда дело дойдет до написания кода. Можно привести следующие причины, побуждающие прибегать к их использованию:
• получение общего представления о системе. Графические модели помогают быстро получить общее представление о системе, сказать о том, какого рода абстракции существуют в системе и какие ее части нуждаются в дальнейшем уточнении;
• общение с экспертами организации. Графические модели образуют внешнее представление системы и объясняют, что эта система будет делать;
• изучение методов проектирования. Множество людей отмечает наличие серьезных трудностей, связанных, например, с освоением объектно-ориентированных методов, и, в первую очередь, смену парадигмы. В некоторых случаях переход к объектно-ориентированным методам происходит относительно безболезненно. В других случаях при работе с объектами приходится сталкиваться с рядом препятствий, особенно в части максимального использования их потенциальных возможностей. Графические средства позволяют облегчить решение этой проблемы.
В процессе создания ПО, автоматизирующего деятельность некоторой организации, используются следующие виды моделей:
• модели деятельности организации (или модели бизнес-процессов):
модели «AS-IS» («как есть»), отражающие существующее на момент обследования положение дел в организации и позволяющие понять, каким образом функционирует данная организация, а также выявить узкие места и сформулировать предложения по улучшению ситуации;
модели «AS-TO-BE» («как должно быть»), отражающие представление о новых процессах и технологиях работы организации. Переход от модели «AS-IS» к модели «AS-TO-BE» может выполняться двумя способами:
1) совершенствованием существующих технологий на основе оценки их эффективности;
2) радикальным изменением технологий и перепроектированием (реинжинирингом) бизнес-процессов.
• модели проектируемого ПО, которые строятся на основе модели «AS-TO-BE», уточняются и детализируются до необходимого уровня.
Состав моделей, используемых в каждом конкретном проекте, и степень их детальности в общем случае (как для структурного, так и для объектно-ориентированного подхода) зависят от следующих факторов:
• сложности проектируемой системы;
• необходимой полноты ее описания;
• знаний и навыков участников проекта;
• времени, отведенного на проектирование.
Методология объектно-ориентированного программирования пришла на смену структурному программированию, когда стало очевидно, что традиционные методы структурного программирования не способны справиться ни с растущей сложностью программ и их разработкой, ни с повышением их надежности. Во второй половине 1980-х годов возникла настоятельная потребность в новой методологии программирования, которая бы позволила решить весь этот комплекс проблем. Такой методологией стало объектно-ориентированное программирование (ООП).
Объектно-ориентированное программирование (ООП, Object-Oriented Programming) - совокупность принципов, технологий, а также инструментальных средств для создания программных систем на основе архитектуры взаимодействия объектов.
В отличие от структурного подхода, основанного на функциональной декомпозиции программ, в объектно-ориентированном подходе в качестве отдельных структурных единиц программы рассматриваются не процедуры и функции, а классы и объекты с соответствующими свойствами и методами. Как следствие, программа перестала быть последовательностью предопределенных на этапе кодирования действий, а преобразовалась в событийно управляемую. Последнее обстоятельство доминирует и при разработке широкого круга современных приложений. В этом случае каждая программа представляет собой бесконечный цикл ожидания заранее определенных событий. Инициаторами событий могут быть другие программы или пользователи, а при наступлении отдельного события программа выходит из состояния ожидания и реагирует на это него вполне адекватным образом.
Объектно-ориентированная методология включает в себя:
• объектно-ориентированный анализ (OOA),
• объектно-ориентированное проектирование (OOD),
• объектно-ориентированное программирование (OOP).
Объектно-ориентированный анализ направлен на создание моделей, более близких к реальности, с использованием объектно-ориентированного подхода; это методология при которой требования формируются на основе понятий классов и объектов, составляющих словарь предметной области.
Предметная область – часть реального мира, которая имеет существенное значение или непосредственное отношение к процессу функционирования программы.
Объектно-ориентированное проектирование – это методология проектирования, соединяющая в себе процесс объектной декомпозиции и приёмы представления как логической и физической, так статической и динамической моделей проектируемой системы.
Объектно-ориентированное программирование – это методология программирования, которая основана на представлении программы в виде совокупности объектов, каждый из которых является реализацией определённого класса, а классы образуют иерархию на принципах наследуемости.
В основе объектно-ориентированного подхода (ООП) лежит объектная декомпозиция, при этом статическая структура системы описывается в терминах объектов и связей между ними, а поведение системы описывается в терминах обмена сообщениями между объектами. Каждый объект системы обладает своим собственным поведением, моделирующим поведение объекта реального мира.
Проблемы, стимулировавшие развитие ООП:
• необходимость повышения производительности разработки за счет многократного (повторного) использования ПО;
• необходимость упрощения сопровождения и модификации разработанных систем (локализация вносимых изменений);
• облегчение проектирования систем (за счет сокращения семантического разрыва между структурой решаемых задач и структурой ПО).
Объектная модель является наиболее естественным способом представления реального мира. В разделе «Теория классификации» Британской энциклопедии сказано следующее:
«В постижении реального мира люди пользуются тремя методами, организующими их мышление:
(1) разделение окружающей действительности на конкретные объекты и их атрибуты (например, когда явно различаются понятия дерева и его высоты или пространственного расположения по отношению к другим объектам);
(2) различие между целыми объектами и их составными частями (например, ветви являются составными частями дерева);
(3) формирование и выделение различий между различными классами объектов (например, между классом всех деревьев и классом всех камней.)»
Понятие «объект» впервые было использовано около 30 лет назад в технических средствах при попытках отойти от традиционной архитектуры фон Неймана и преодолеть барьер между высоким уровнем программных абстракций и низким уровнем абстрагирования на уровне компьютеров. С объектно-ориентированной архитектурой также тесно связаны объектно-ориентированные операционные системы. Однако наиболее значительный вклад в объектный подход был внесен объектными и объектно-ориентированными языками программирования: Simula (1967), Smalltalk (1970-е гг.), C++ (1980-е гг.) и языком моделирования UML (1990-е гг.). На объектный подход оказали влияние также развивавшиеся достаточно независимо методы моделирования данных, в особенности модель «сущность-связь».
Концептуальной основой объектно-ориентированного подхода является объектная модель. Основными принципами ее построения являются :
• абстрагирование (abstraction);
• инкапсуляция (encapsulation);
• модульность (modularity);
• иерархия (hierarchy).
Абстрагирование — это выделение наиболее важных, существенных характеристик некоторого объекта, которые отличают его от всех других видов объектов и, таким образом, четко определяют его концептуальные границы с точки зрения дальнейшего рассмотрения и анализа, и игнорирование менее важных или незначительных деталей. Абстрагирование позволяет управлять сложностью системы, концентрируясь на существенных свойствах объекта. Абстрагирование концентрирует внимание на внешних особенностях объекта и позволяет отделить самые существенные особенности его поведения от деталей их реализации. Выбор правильного набора абстракций для заданной предметной области представляет собой главную задачу объектно-ориентированного проектирования. Абстракция зависит от предметной области и точки зрения — то, что важно в одном контексте, может быть не важно в другом. Объекты и классы — основные абстракции предметной области.
Инкапсуляция — физическая локализация свойств и поведения в рамках единственной абстракции (рассматриваемой как «черный ящик»), скрывающая их реализацию за общедоступным интерфейсом.
Инкапсуляция - это процесс отделения друг от друга отдельных элементов объекта, определяющих его устройство и поведение. Инкапсуляция служит для того, чтобы изолировать интерфейс объекта, отражающий его внешнее поведение, от внутренней реализации объекта. Объектный подход предполагает, что собственные ресурсы, которыми могут манипулировать только операции самого объекта, скрыты от внешней среды. Абстрагирование и инкапсуляция являются взаимодополняющими: абстрагирование фокусирует внимание на внешних особенностях объекта, а инкапсуляция (или иначе ограничение доступа) не позволяет объектам-пользователям различать внутреннее устройство объекта.
По-другому инкапсуляцию можно описать, сказав, что приложение разделяется на небольшие фрагменты связанной функциональности. Допустим, в банковской системе имеется информация, касающаяся банковского счета, такая как номер счета, баланс, имя и адрес его владельца, тип счета, начисляемые на него проценты и дата открытия. Со счетом также связаны определенные действия: открыть, закрыть его, положить или снять некоторую сумму денег, а также изменить тип, владельца или адрес. Вся эта информация и действия (поведение) совместно инкапсулируются в объект «счет». В результате все изменения банковской системы, связанные со счетами, могут быть реализованы в одном только объекте «счет».
Еще одним преимуществом инкапсуляции является ограничение последствий изменений, вносимых в систему. Применим принцип инкапсуляции к банковской системе. Допустим, управление банка постановило, что если клиент имеет кредитный счет, то этот кредит может быть использован как овердрафт на его счете «до востребования». В не инкапсулированной системе модификация начинается с узконаправленного анализа изменений, которые необходимо будет внести в систему. Как правило, неизвестно, где в системе находятся все обращения к функции снятия со счета, поэтому приходится искать их везде. После того, как они найдены, нужно осуществить в них некоторые изменения, чтобы реализовать новые требования. Если работать тщательно, то, вероятно, можно будет обнаружить около 80% случаев использования данной функции. В инкапсулированной системе не требуется осуществлять такой детальный анализ. Достаточно посмотреть на модель системы и определить, где инкапсулировано соответствующее поведение (действие снятия со счета). После его локализации остается внести требуемые поправки один раз только в этом объекте, и задача выполнена.
Инкапсуляция подобна понятию сокрытия информации (information hiding). Это возможность скрывать многочисленные детали объекта от внешнего мира. Внешний мир объекта — это все, что находится вне его, включая остальную часть системы. Сокрытие информации предоставляет то же преимущество, что и инкапсуляция, - гибкость.
Модульность — это свойство системы, связанное с возможностью ее декомпозиции на ряд внутренне сильно сцепленных, но слабо связанных между собой подсистем (модулей). Модульность снижает сложность системы, позволяя выполнять независимую разработку отдельных модулей. Инкапсуляция и модульность создают барьеры между абстракциями.
Иерархия — это ранжированная или упорядоченная система абстракций, расположение их по уровням. Основными видами иерархических структур применительно к сложным системам являются структура классов (иерархия по номенклатуре) и структура объектов (иерархия по составу). Примерами иерархии классов являются простое и множественное наследование (один класс использует структурную или функциональную часть соответственно одного или нескольких других классов), а иерархии объектов - агрегация.
К основным понятиям объектно-ориентированного подхода (элементам объектной модели) относятся:
• объект;
• класс;
• атрибут;
• операция;
• полиморфизм (интерфейс);
• компонент;
• связи.
Объект определяется как осязаемая сущность (tangible entity) — предмет или явление (процесс), имеющая четко определяемое поведение. Объект может представлять собой абстракцию некоторой сущности предметной области (объект реального мира) или программной системы (архитектурный объект). Любой объект обладает состоянием (state), поведением (behavior) и индивидуальностью (identity).
Состояние объекта - одно из возможных условий, в которых он может существовать, оно изменяется со временем. Состояние объекта характеризуется перечнем всех возможных (статических) свойств данного объекта и текущими значениями (динамическими) каждого из этих свойств. Состояние объекта определяется значениями его свойств (атрибутов) и связями с другими объектами.
Поведение определяет действия объекта и его реакцию на запросы от других объектов. Поведение характеризует воздействие объекта на другие объекты, изменяющее их состояние. Иначе говоря, поведение объекта полностью определяется его действиями. Поведение представляется с помощью набора сообщений, воспринимаемых объектом (операций, которые может выполнять объект).
Каждый объект обладает уникальной индивидуальностью. Индивидуальность — это свойства объекта, отличающие его от всех других объектов.
Структура и поведение схожих объектов определяют общий для них класс. Термины «экземпляр класса» и «объект» являются эквивалентными.
Графическое представление объектов в языке моделирования UML (который будет рассматриваться в подразд. 2.5) показано на рисунке 1.

Рисунок 1 - Графическое представление объектов
Класс — это множество объектов, связанных общностью свойств, поведения, связей и семантики. Класс инкапсулирует (объединяет) в себе данные (атрибуты) и поведение (операции). Класс является абстрактным определением объекта и служит в качестве шаблона для создания объектов. Графическое представление класса в языке UML показано на рис. 2.38. Класс изображается в виде прямоугольника, разделенного на три части. В первой содержится имя класса, во второй — его атрибуты. В последней части содержатся операции класса, отражающие его поведение (действия, выполняемые классом).
Любой объект является экземпляром (instance) класса. Определение классов и объектов — одна из самых сложных задач объектно-ориентированного проектирования.
Атрибут — поименованное свойство класса, определяющее диапазон допустимых значений, которые могут принимать экземпляры данного свойства.
Атрибут - это элемент информации, связанный с классом. Например, у класса Company (Компания) могут быть атрибуты Name (Название), Address (Адрес) и NumberOfEmployees (Число служащих).

Рисунок 2 - Графическое представление класса
Так как атрибуты содержатся внутри класса, они скрыты от других классов. В связи с этим может понадобиться указать, какие классы имеют право читать и изменять атрибуты. Это свойство называется видимостью атрибута (attribute visibility).
У атрибута можно определить три возможных значения этого параметра. Рассмотрим каждый из них в контексте примера (см. рисунок 2). Пусть имеется класс Работник (Employee) с атрибутом Адрес (Address) и класс Company:
Public (общий, открытый). Это значение видимости предполагает, что атрибут будет виден всеми остальными классами. Любой класс может просмотреть или изменить значение атрибута. В таком случае класс Company может изменить значение атрибута Address класса Employee. В соответствии с нотацией UML общему атрибуту предшествует знак «+».
Private (закрытый, секретный). Соответствующий атрибут не виден никаким другим классом. Класс Employee будет знать значение атрибута Address и сможет изменять его, но класс Company не сможет его ни увидеть, ни редактировать. Если это понадобится, он должен попросить класс Employee просмотреть или изменить значение этого атрибута, что обычно делается с помощью общих операций. Закрытый атрибут обозначается знаком «-» в соответствии с нотацией UML.
Protected (защищенный). Такой атрибут доступен только самому классу и его потомкам в иерархии наследования.
Допустим, имеется два различных типа сотрудников — с почасовой оплатой и на окладе. Таким образом, потомками класса Employee будут два класса — HourlyEmp и SalariedEmp. Защищенный атрибут Address можно просмотреть или изменить из классов Employee, HourlyEmp и SalariedEmp, но не из класса Company. Нотация UML для защищенного атрибута — это знак «#».
В общем случае атрибуты рекомендуется делать закрытыми или защищенными. При этом удается избежать ситуации, когда значение атрибута изменяется всеми классами системы. Вместо этого логика изменения атрибута будет заключена в том же классе, что и сам этот атрибут.
Определенное воздействие одного объекта на другой с целью вызвать соответствующую реакцию называется операцией. Операция — это реализация услуги, которую можно запросить у любого объекта данного класса.
Операции отражают поведение объекта. Операция-запрос не изменяет состояния объекта. Операция-команда может изменить состояние объекта. Результат операции зависит от текущего состояния объекта.
Как правило, в объектных и объектно-ориентированных языках программирования операции, выполняемые над данным объектом, называются методами и являются составной частью определения класса.
Операции реализуют связанное с классом поведение (иначе говоря, реализуют обязанности класса — responsibilities). В широком смысле обязанности класса делятся на две категории.
Знание (определяется атрибутами класса):
• наличие информации о данных или вычисляемых величинах;
• наличие информации о связанных объектах.
Действие (определяется операциями класса):
• выполнение некоторых действий самим объектом;
• инициация действий других объектов;
• координация действий других объектов.
Операция включает три части — имя, параметры и тип возвращаемого значения. Параметры - это аргументы, получаемые операцией «на входе». Тип возвращаемого значения относится к результату действия операции. В языке UML операции имеют следующую нотацию:
Имя Операции (аргумент1: тип данных аргумента1, аргумент2: тип данных аргумента2,...): тип возвращаемого значения
Существуют четыре различных типа операций.
• Операции реализации (implementor operations) реализуют некоторые функции (процедуры). Такие операции выявляются путем анализа диаграмм взаимодействия UML.
• Операции управления (manager operations) управляют созданием и уничтожением объектов. В эту категорию попадают конструкторы и деструкторы классов.
• Атрибуты обычно бывают закрытыми или защищенными. Тем не менее, другие классы иногда должны просматривать или изменять их значения. Для этого существуют операции доступа (access operations).
• Вспомогательными (helper operations) называются такие операции класса, которые необходимы ему для выполнения его обязанностей, но о которых другие классы не должны ничего знать. Это закрытые и защищенные операции класса.
Полиморфизм — это способность скрывать множество различных реализаций под единственным общим интерфейсом.
Существует несколько видов полиморфизма. Два наиболее различных из них: это специальный полиморфизм (или «ad hoc полиморфизм») и параметрический полиморфизм. Кратко специальный полиморфизм описывается принципом «много реализаций с похожими интерфейсами», а параметрический полиморфизм — «одна реализация с обобщённым интерфейсом».
Интерфейс — совокупность операций, определяющих набор услуг класса или компонента. Интерфейс не определяет внутреннюю структуру, все его операции имеют открытую видимость
Полиморфизм тесно связан с наследованием. Наследование означает построение новых классов на основе существующих с возможностью добавления или переопределения свойств (атрибутов) и поведения (операций).
Объектно-ориентированная система изначально строится с учетом ее эволюции. Наследование и полиморфизм обеспечивают возможность определения новой функциональности классов с помощью создания производных классов — потомков базовых классов. Потомки наследуют характеристики родительских классов без изменения их первоначального описания и добавляют при необходимости собственные структуры данных и методы. Определение производных классов, при котором задаются только различия или уточнения, в огромной степени экономит время и усилия при производстве и использовании спецификаций и программного кода.
Компонент — относительно независимая и замещаемая часть системы, выполняющая четко определенную функцию в контексте заданной архитектуры. Компонент представляет собой физическую реализацию проектной абстракции и может быть:
• компонентом исходного кода;
• компонентом времени выполнения (run time);
• исполняемым компонентом.
Компонент обеспечивает физическую реализацию набора интерфейсов.
Между элементами объектной модели существуют различные виды связей. К основным типам связей относятся связи ассоциации, зависимости и обобщения.
Ассоциация (association) — это семантическая связь между классами. Ее изображают на диаграмме классов в виде обыкновенной линии (рис. 3). Ассоциация отражает структурные связи между объектами различных классов.

Рисунок 3 - Ассоциация
Агрегация (aggregation) представляет собой форму ассоциации — более сильный тип связи между целым (составным) объектом и его частями (компонентными объектами).
Существуют четыре возможных семантики (смысла) для агрегации:
1. агрегация типа «Безраздельно обладает»;
2. агрегация типа «Обладает»;
3. агрегация типа «Включает»;
4. агрегация типа «Участник».
Агрегация типа «Безраздельно обладает» устанавливает следующее:
• между компонентными объектами и их составными объектами установлено отношение зависимости по существованию (следовательно, удаление составного объекта распространяется вниз по иерархии отношения, так что связанные компонентные объекты также удаляются);
• агрегация транзитивна (если объект С1 является частью объекта В1, а В1 — частью А1, тогда С1 является частью А1);
• агрегация асимметрична (нерефлексивна) (если объект В1 является частью объекта А1, то объект А1 не является частью В1);
• агрегация стационарна (если объект В1 является частью объекта А1, то он не может быть частью объекта Ai (i ≠ 1)).
Агрегация типа «Обладает» поддерживает первые три свойства агрегации «Безраздельно обладает», к которым относятся:
• зависимость по существованию;
• транзитивность;
• асимметричность.
Агрегация типа «Включает» слабее, чем агрегация типа «Обладает», она поддерживает транзитивность и асимметричность.
Агрегация типа «Участник» обладает свойством целенаправленного группирования независимых объектов — группирования, при котором не делается предположений относительно свойства зависимости по существованию, транзитивности, асимметричности или стационарности. Компонентный объект в агрегации типа «Участник» может одновременно принадлежать более чем одному составному объекту.
Язык UML обеспечивает ограниченную поддержку агрегации. Сильная форма агрегации является в UML композицией. В композиции составной объект может физически содержать компонентные объекты. Компонентный объект может принадлежать только одному составному объекту. Композиция языка UML в большей или меньшей степени соответствует агрегациям типа «Безраздельно обладает» и «Обладает».
Слабая форма агрегации в UML называется просто агрегацией. При этом составной объект физически не содержит компонентный объект. Один компонентный объект может обладать несколькими связями ассоциации или агрегации. Иначе говоря, агрегация в языке UML соответствует агрегациям типа «Включает» и «Участник».
Агрегация изображается линией между классами с ромбом на стороне целого объекта (рисунок 4). Сплошной ромб представляет композицию (рисунок 5).


Рисунок 4 - Агрегация

Рисунок 5 - Композиция
Хотя связи ассоциации и агрегации двунаправленные по умолчанию, часто накладываются ограничения на направление навигации (только в одном направлении). Если введено ограничение по направлению, то добавляется стрелка на конце связи. Направление ассоциации можно определить, изучая сообщения между классами. Если все сообщения на них отправляются только одним классом и принимаются только другим классом, но не наоборот, между этими классами имеет место однонаправленная связь. Если хотя бы одно сообщение отправляется в обратную сторону, ассоциация должна быть двунаправленной.
Ассоциации могут быть рефлексивными. Рефлексивная ассоциация предполагает, что один экземпляр класса взаимодействует с другими экземплярами этого же класса.
Связи можно уточнить с помощью имен связей или ролевых имен. Имя связи - это обычно глагол или глагольная фраза, описывающая, зачем она нужна. Например, между классом Person (человек) и классом Company (компания) может существовать ассоциация. Если человек является сотрудником компании, ассоциацию можно назвать «employs» (нанимает) (см. рисунок 3).
Имена у связей определять не обязательно. Обычно это делают, если причина создания связи не очевидна. Имя показывают около линии соответствующей связи.
Для уточнения роли, которую играет каждый класс в связях ассоциации или агрегации, применяют ролевые имена (рисунок 6). Возвращаясь к примеру с классами Person и Company, можно сказать, что класс Person играет роль сотрудника класса Company. Ролевые имена — это обычно имена существительные или основанные на них фразы, их показывают на диаграмме рядом с классом, играющим соответствующую роль. Как правило, пользуются или ролевым именем, или именем связи, но не обоими сразу. Как и имена связей, ролевые имена не обязательны, их дают, только если смысл связи не очевиден.

Рисунок 6 - Ролевые имена
Мощность (multiplicity) показывает, как много объектов участвует в связи.
Мощность — это число объектов одного класса, связанных с одним объектом другого класса. Понятие мощности связи в объектной модели аналогично понятиям мощности и класса принадлежности связи в модели «сущность-связь» (с точностью до расположения показателя мощности на диаграмме). Для каждой связи можно обозначить два показателя мощности — по одному на каждом конце связи.
В языке UML приняты следующие нотации для обозначения мощности.

Например, при разработке системы регистрации курсов в университете можно определить классы Course (учебный курс) и Student (студент). Между ними установлена связь, означающая посещение курсов студентами. Если один студент может посещать от нуля до четырех курсов, а на одном курсе могут заниматься от 10 до 20 студентов, то на диаграмме классов это можно изобразить следующим образом (рисунок 7).

Рисунок 7 - Мощность связи
Частным случаем ассоциации является ассоциация-класс (Association class), которая обладает как свойствами класса, так и свойствами ассоциации. Ассоциация-класс — это место, где хранятся относящиеся к ассоциации атрибуты и операции. Экземплярами ассоциации-класса являются связи, у которых есть не только ссылки на объекты, но и значения атрибутов. Ассоциация-класс подобна связи с атрибутами в модели «сущность-связь».
Допустим, что имеются два класса, Student и Course, и возникла необходимость добавить атрибут Grade (оценка). В таком случае возникает вопрос, в какой класс надо его добавить. Если поместить его внутри класса Student, то придется вводить его для каждого посещаемого студентом курса, что слишком сильно увеличит размер этого класса. Если же поместить его внутри класса Course, то придется задавать его для каждого посещающего этот курс студента.
Чтобы решить эту проблему, можно создать ассоциацию-класс. В этот класс следует поместить атрибут Grade, относящийся к связи между курсом и студентом. Нотация UML для ассоциации-класса представлена на рисунке 8.

Рисунок 8 - Ассоциация-класс
Ассоциация-класс определяет дополнительное ограничение, согласно которому двум участвующим в ассоциации объектам может соответствовать только один экземпляр ассоциации-класса. Диаграмма на рис. 2.44 не допускает, чтобы студент мог получать по курсу более чем одну оценку. Если необходимо, чтобы такое допускалось, то ассоциацию-класс Grade следует преобразовать в обычный класс, связанный ассоциациями с классами Student и Course.
Зависимость (dependency) — связь между двумя элементами модели, при которой изменения в спецификации одного элемента могут повлечь за собой изменения в другом элементе. Зависимость — слабая форма связи между клиентом и сервером (клиент зависит от сервера и не имеет знаний о сервере). Зависимость изображается пунктирной линией, направленной от клиента к серверу (рисунок 9).

Рисунок 9 - Зависимость
Зависимость между двумя элементами имеет место в том случае, если изменения в определении одного элемента могут повлечь за собой изменения в другом. Причины для зависимостей могут быть самыми разными: один класс посылает сообщение другому; один класс включает часть данных другого класса; один класс использует другой в качестве параметра операции. Если класс меняет свой интерфейс, то любое сообщение, которое он посылает, может утратить свою силу.
Обобщение (generalization) — связь «тип-подтип» реализует механизм наследования (inheritance). Большинство объектно-ориентированных языков непосредственно поддерживают концепцию наследования. Она позволяет одному классу наследовать все атрибуты, операции и связи другого. В языке UML связи наследования называют обобщениями и изображают в виде стрелок от класса-потомка к классу-предку (рисунок 10).

Рисунок 10 - Обобщение
Общие атрибуты, операции и/или связи отображаются на верхнем уровне иерархии.
Помимо наследуемых, каждый подкласс имеет свои собственные уникальные атрибуты, операции и связи.
Примеры структурного и объектно-ориентированного подхода к разработке приложений
Ниже приведён пример описания проекта программы в технологии структурного программирования с помощью схемы иерархии логических модулей. Программа предназначена для преобразования р-ичного числа представленного строкой в числовой формат. Схема иерархии логических модулей – это результат функциональной декомпозиции программы. Она отражает связь модулей по управлению, т.е. показывает с помощью линий передачи управления, какие модули может вызвать данный модуль. Модуль может вызвать только модули нижележащего уровня непосредственно с ним связанные.
Пример.

Рисунок 11 – Пример перевода числен из одной системы счисления в другую
На рисунке 11 прямоугольниками обозначены логические модули, линиями обозначены связь между модулями по управлению. Каждый модуль управляет вызовом модулей нижележащих уровней непосредственно связанных с ним.
На уровне языка программирования каждый логический модуль может быть реализован в форме подпрограммы (процедуры или функции) или модуля (unit). Выбор формы реализации модуля на языке программирования зависит от размеров логического модуля.
Ниже приведён пример проектирования и реализации программы, предназначенной для преобразования р-ичного числа представленного строкой в числовой формат, в технологии ООП.
Проект программы опишем с помощью диаграммы прецедентов, диаграммы последовательностей и диаграммы классов.
Программа реализует единственный прецедент: полученную от пользователя р-ичную строку преобразует в числовой формат.

Рисунок 12 - Диаграмма прецедентов
Диаграмма прецедентов UML.
Для реализации прецедента мы создаём два объекта: один объект класса TInOut осуществляет ввод исходной строки, проверку строки на соответствие заданному формату и вывод результата, второй объект класса TConvertPToDec – осуществляет преобразование введённой строки в числовой формат. Обмен сообщениями между объектами представлен на диаграмме последовательности.

Рисунок 13 - Обмен сообщениями между объектами
Диаграмма последовательности UML для прецедента.
Классы объектов использованных нами для реализации прецедента связаны между собой отношением зависимости. Это представлено на диаграмме классов.

Рисунок 14 – Зависимости классов объектов
Диаграмма классов UML для прецедента
Типичные приемы моделирования
Простые зависимости
Самым распространенным видом отношения зависимости является соединение между классами, когда один класс использует другой в качестве параметра операции.
Для моделирования такого отношения изобразите зависимость, направленную от класса с операцией к классу, используемому в качестве ее параметра.
Например, на рис. 5.8 показано несколько классов, взятых из системы, управляющей распределением студентов и преподавателей на университетских курсах. Зависимость направлена от класса РасписаниеЗанятий к классу Курс, поскольку последний используется в операциях add и remove класса РасписаниеЗанятий.
Если вы приводите полную сигнатуру операции, как на этом рисунке, то зависимости показывать не обязательно, поскольку имя класса уже явно присутствует в сигнатуре. Иногда продемонстрировать зависимость все же имеет смысл, особенно если сигнатуры операций скрыты или в модели показаны другие отношения, в которых участвует используемый класс.
На рисунке 15 представлена еще одна зависимость, не предполагающая участия классов, а скорее моделирующая обычную для языка C++ идиому.

Рисунок 15 - Отношения зависимости
Стрелка, направленная от класса Итератор, свидетельствует о том, что он использует класс РасписаниеЗанятий, который, однако, об этом ничего не «знает». Зависимость помечена стереотипом friend, который говорит, что она представляет отношение дружественности, как в языке C++.
Одиночное наследование
Моделируя словарь системы, вам часто придется работать с классами, похожими на другие по структуре и поведению. В принципе их можно моделировать как различные, независимые друг от друга абстракции. Но лучше выделить одинаковые свойства и сформировать на их основе общие классы, которым наследуют специализированные.
Моделирование отношений наследования осуществляется в таком порядке:
1. Найдите атрибуты, операции и обязанности, общие для двух или более классов из данной совокупности.
2. Вынесите эти элементы в некоторый общий класс (если надо, создайте но¬вый, но следите, чтобы уровней не оказалось слишком много).
3. Отметьте в модели, что более специализированные классы наследуют более общим, включив отношение обобщения, направленное от каждого потомка к его родителю.
На рисунке 16 вы видите несколько классов, взятых из приложения по организации работы трейдеров. Здесь показано отношение обобщения, которое от четырех классов - РасчетныйСчет, Акция, Облигация и Собственность - направлено к более общему классу ЦенныеБумаги. Он является родителем, а остальные - его потомками. Каждый специализированный класс - это частный случай класса ЦенныеБумаги. Обратите внимание, что в классе ЦенныеБумаги есть две операции - presentValue (текущаяСтоимость) и history (история). Это значит, что все его потомки наследуют данные операции, а заодно и все остальные атрибуты и операции родителя, которые могут не изображаться на рисунке.
Имена ЦенныеБумаги и presentValue на рисунке намеренно выделены курсивом. Дело в том, что, создавая иерархию подобного рода, часто приходится сталкиваться с нелистовыми классами, которые неполны или для которых не может существовать объектов. Такие классы называются абстрактными, и на языке UML их названия пишутся курсивом, как в приведенном примере. Данное соглашение применимо и к операциям (например, presentValue); оно означает, что у операции есть сигнатура, но в других отношениях она неполна и требует реализации на более низком уровне абстракции. В нашем примере все четыре непосредственных потомка класса ЦенныеБумаги конкретны (то есть не абстрактны) и реализуют операцию presentValue.

Рисунок 16 - Отношения наследования
Иерархия «обобщение/специализация» не обязательно ограничивается двумя уровнями. Как видно из рисунка, вполне допустимо существование более двух уровней наследования. АкцияСМалымКапиталом и АкцияСБольшимКапиталом -потомки класса Акция, который, в свою очередь, является потомком класса ЦенныеБумаги. Последний является базовым классом, поскольку не имеет родителей. Классы же АкцияСМалымКапиталом и АкцияСБольшимКапиталом - листовые, поскольку не имеют потомков. Наконец, класс Акция имеет как родителей, так и потомков, а следовательно, не является ни листовым, ни базовым.
Хотя на данном рисунке это не продемонстрировано, можно создавать классы, имеющие более одного родителя. В таком случае речь идет о множественном наследовании, которое означает, что данный класс перенимает атрибуты, операции и ассоциации всех своих родителей.
Разумеется, в графе наследования не допускаются циклы - класс не может быть собственным родителем.
Структурные отношения
Отношения зависимости и обобщения применяются при моделировании классов, которые находятся на разных уровнях абстракции или имеют различную значимость. Что касается отношения зависимости, один класс зависит от другого, но тот может ничего не «знать» о наличии первого. Когда речь идет об отношении обобщения, класс-потомок наследует своему родителю, но сам родитель о нем не осведомлен. Другими словами, отношения зависимости и обобщения являются односторонними.
Ассоциации предполагают участие равноправных классов. Если между двумя классами установлена ассоциация, то каждый из них каким-то образом зависит от другого, и навигацию можно осуществлять в обоих направлениях. В то время как зависимость - это отношение использования, а обобщение - отношение «является», ассоциации определяют структурный путь, обусловливающий взаимодействие объектов данных классов. По умолчанию ассоциации являются двунаправленными, но вы можете оставить только одно направление.
Моделирование структурных отношений производится следующим образом:
Определите ассоциацию для каждой пары классов, между объектами которых надо будет осуществлять навигацию. Это взгляд на ассоциации с точки зрения данных.
Если объекты одного класса должны будут взаимодействовать с объектами другого иначе, чем в качестве параметров операции, следует определить между этими классами ассоциацию. Это взгляд на ассоциации с точки зрения поведения.
Для каждой из определенных ассоциаций задайте кратность (особенно если она не равна *, то есть значению по умолчанию) и имена ролей (особенно если это помогает объяснить модель).
Если один из классов ассоциации структурно или организационно представляет собой целое в отношении классов на другом конце ассоциации, выглядящих как его части, пометьте такую ассоциацию как агрегирование.
Как узнать, когда объекты данного класса должны взаимодействовать с объектами другого класса? Для этого рекомендуется воспользоваться CRC-карточками и анализом прецедентов. Эти методы очень помогают при рас¬смотрении структурных и поведенческих вариантов функционирования системы. Если в результате обнаружится взаимодействие между классами, специфицируйте ассоциацию.
На рисунке 17 изображены классы, взятые из вузовской информационной системы. В нижней части диаграммы находятся классы Студент, Курс и Преподаватель. Между классами Студент и Курс существует ассоциация, показывающая, что студенты посещают курсы. Каждый студент может посещать любое число курсов, и на каждый курс может приходить любое количество студентов.
Аналогичным образом между классами Курс и Преподаватель определена ассоциация, показывающая, что преподаватель читает курс. Для каждого курса должен быть хотя бы один преподаватель, и каждый преподаватель может вести любое количество курсов (в том числе и ни одного).
Отношения между классом Вуз и классами Студент и Факультет слегка отличаются друг от друга, хотя оба являются отношениями агрегирования.

Рисунок 17 - Структурные отношения
В вузе может быть любое количество студентов (включая ноль), и каждый студент может обучаться в одном или нескольких вузах; вуз может состоять из одного или нескольких факультетов, но каждый факультет принадлежит одному и только одному вузу. Отношение между классами Вуз и Факультет называют композитным агрегированием. В принципе можно было бы обойтись без отношений агрегирования и использовать простые ассоциации, определяя при этом Вуз как целое, а Студента и Факультет - как его части. Тем самым вы ясно показываете, какой из классов организационно стоит выше остальных. Так, вузы в какой-то степени определяются своими студентами и факультетами. В то же время студенты и факультеты вообще не могут существовать вне связи со своим вузом, и в какой-то мере он формирует их облик.
Видно также, что между классами Факультет и Преподаватель установле¬ны две ассоциации. Одна из них показывает, что каждый преподаватель работает на одном или нескольких факультетах, и на каждом факультете должен быть, по меньшей мере, один преподаватель. Здесь мы имеем дело с агрегированием, так как организационно факультеты находятся на более высоком уровне вузовской структуры, чем преподаватели. Другая ассоциация показывает, что каждым факультетом управляет только один преподаватель - декан. Согласно данной модели, преподаватель может быть деканом только одного факультета, причем некоторые преподаватели не являются деканами.
Примечание. Разрабатывая подобную модель, вы можете обнаружить, что вышеприведенный пример не соответствует вашим условиям. В вузе может не быть факультетов. Деканы не всегда обязаны преподавать, а с другой стороны, встречаются студенты, одновременно работающие преподавателями. Все это не означает, что данная модель неверна, - просто она иллюстрирует один из частных случаев. Нельзя моделировать в отрыве от реальности, и всякая модель зависит от того, как вы собираетесь ее использовать.
Советы
При моделировании отношений в UML соблюдайте следующие правила:
• используйте зависимость, только если моделируемое отношение не является структурным;
• используйте обобщение, только если имеет место отношение типа «является»;
• множественное наследование часто можно заменить агрегированием;
• остерегайтесь циклических отношений обобщения;
• поддерживайте баланс в отношениях обобщения: иерархия наследования не должна быть не слишком глубокой (желательно не более пяти уровней), ни слишком широкой (лучше прибегнуть к промежуточным абстрактным классам);
• применяйте ассоциации прежде всего там, где между объектами существуют структурные отношения.
• выбрав один из стилей оформления линий (прямые или наклонные), в даль¬нейшем старайтесь его придерживаться. Прямые линии подчеркивают, что соединения идут от родственных сущностей к одному общему родителю.Наклонные линии позволяют существенно сэкономить пространство в сложных диаграммах. Если вы хотите привлечь внимание к разным группам отношений, применяйте одновременно оба типа линий;
• избегайте пересечения линий;
• показывайте только такие отношения, которые необходимы для понимания особенностей группирования элементов модели; скрывайте несущественные (особенно избыточные) ассоциации.